﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;
using System.Windows.Forms;
using Shoozla.ViewModel;
using System.Linq;


namespace Shoozla
{
    public partial class FolderExplorerControl : System.Windows.Controls.UserControl
    {
        private readonly object _dummyNode = null;
        private Dictionary<String,DirectoryInfo> _selectedFolders;
      
        public event FolderChangedDelegate SelectetdFolderChanged;
        public event FoldersChangedDelegate AddedFolders;
        public event FolderChangedDelegate RemovedFolder;
        public delegate void FolderChangedDelegate(DirectoryInfo folder);
        public delegate void FoldersChangedDelegate(List<DirectoryInfo> folder);

        private bool IgnoreEvents = false; //used for recursion


        public FolderExplorerControl()
        {
           InitializeComponent();
           DataContext = new FolderExplorerViewModel();
            _dummyNode = new object();
            _selectedFolders = new Dictionary<String, DirectoryInfo>();
           foldersTree.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(foldersTree_SelectedItemChanged);
        }

        void folder_UnChecked(object sender, RoutedEventArgs e)
        {
            System.Windows.Controls.CheckBox c = sender as System.Windows.Controls.CheckBox;
            TreeViewItem rootItem = (TreeViewItem)c.Tag;
            DirectoryInfo dir = (DirectoryInfo)rootItem.Tag;

            if (rootItem == null)
                return;

            if (_selectedFolders.ContainsKey(dir.FullName))
                _selectedFolders.Remove(dir.FullName);

            if (RemovedFolder != null)
                RemovedFolder.BeginInvoke((DirectoryInfo)rootItem.Tag,null,null);
           
            //uncheck all the children
            CheckUntil(rootItem, false);         

        }

        void folder_Checked(object sender, RoutedEventArgs e)
        {
            
            System.Windows.Controls.CheckBox c = sender as System.Windows.Controls.CheckBox;
            TreeViewItem rootItem = (TreeViewItem)c.Tag;
            DirectoryInfo dir = (DirectoryInfo)rootItem.Tag;

            if (rootItem == null)
                return;

            if (_selectedFolders.ContainsKey(dir.FullName))
                return;
            else
                //this is a new folder, continue to read and check all the children
                _selectedFolders.Add(dir.FullName,dir);

            if (IgnoreEvents)
                return; //doing recursion, not notifying the main

            //check all the children
            IgnoreEvents = true;
            List<DirectoryInfo> children = CheckUntil(rootItem, true);
            foreach(DirectoryInfo d in children)
                if(!_selectedFolders.ContainsKey(d.FullName))
                        _selectedFolders.Add(d.FullName,d);
            
            IgnoreEvents = false;

            if (AddedFolders != null)
                AddedFolders.BeginInvoke(_selectedFolders.Values.ToList<DirectoryInfo>(), null, null);

            rootItem.IsSelected = true;
        }

        void folder_Expanded(object sender, RoutedEventArgs e)
        {
            TreeViewItem item = (TreeViewItem)sender;

            if (sender == null)
                return;

            if (item.Items.Count == 1 && item.Items[0] == _dummyNode)
            {
                item.Items.Clear();
                try
                {
                    foreach (DirectoryInfo subFolder in ((DirectoryInfo)item.Tag).EnumerateDirectories())
                    {
                        TreeViewItem subitem = new TreeViewItem();
                        subitem.Header = subFolder.Name;
                        subitem.Tag = subFolder;
                        subitem.Items.Add(_dummyNode);
                        TreeViewItemProps.SetIsChecked(subitem, false);
                        //to not insert duplicate handlers
                        //subitem.Expanded -= folder_Expanded;
                        //subitem.Collapsed -= folder_Collpased;

                        //subitem.Expanded += folder_Expanded;
                        //subitem.Collapsed += folder_Collpased;
                        item.Items.Add(subitem);
                    }
                }
                catch (Exception) { }
                finally
                {
                    // item.IsSelected = true;
                }
            }
        }

        void folder_Collpased(object sender, RoutedEventArgs e)
        {        
        }

        void foldersTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (SelectetdFolderChanged != null)
            {
                TreeViewItem item = (TreeViewItem)foldersTree.SelectedItem;
                DirectoryInfo selectedFolder = (DirectoryInfo)item.Tag;
                SelectetdFolderChanged.BeginInvoke(selectedFolder,null,null);
            }
        }

        public void AddFolderToView(DirectoryInfo folder)
        {
            try
            {
                if (folder != null)
                {
                    int index = FolderAlreadyRead(folder);
                    if (index >= 0)
                    {
                        //folder already read 
                        ExpandUntil(folder,(TreeViewItem)foldersTree.Items[index]);
                        return;
                    }

                    //add the item as root
                    TreeViewItem mainItem = new TreeViewItem();
                    mainItem.Header = folder.Name;
                    mainItem.Tag = folder;
                    mainItem.Items.Add(_dummyNode);
                    mainItem.Expanded += folder_Expanded;
                    mainItem.Collapsed += folder_Collpased;

                    // Apply the attached property so that 
                    // the triggers know that this is root item.
                    TreeViewItemProps.SetIsRootLevel(mainItem, true);
                    TreeViewItemProps.SetIsChecked(mainItem, false);

                    foldersTree.Items.Add(mainItem);
                    mainItem.IsSelected = true;
                    mainItem.IsExpanded = true;
                   // folder_Expanded(mainItem, null);
                    ReadChildren(mainItem); //read all the children, but not display
                    ((FolderExplorerViewModel)DataContext).ShowHint = false;
                }
            }
            catch (UnauthorizedAccessException accEx)
            {
                AppModel.LogEntry("[ERROR] AddFolderToView: " + accEx.Message);
            }
        }

        private int FolderAlreadyRead(DirectoryInfo folder)
        {
            foreach (TreeViewItem i in foldersTree.Items)
            {
                DirectoryInfo dir = i.Tag as DirectoryInfo;
                if (dir != null)
                { 
                    if(folder.FullName.StartsWith(dir.FullName))
                        return foldersTree.Items.IndexOf(i);
                }
            }
            return -1;
        }

        private void ExpandUntil(DirectoryInfo target, TreeViewItem item)
        {
            foreach (TreeViewItem i in item.Items)
            {
                DirectoryInfo dir = i.Tag as DirectoryInfo;
                if (dir != null)
                {
                    if (target.FullName == dir.FullName)
                    {
                        i.IsSelected = true;
                        return;
                    }

                    if (target.FullName.StartsWith(dir.FullName))
                    {
                        i.IsExpanded = true;
                        ExpandUntil(target, i);
                    }                  
                }
            }
        }

        private void ReadChildren(TreeViewItem item)
        {
            folder_Expanded(item, null);

            for (int i = 0; i < item.Items.Count; i++)
            {
                try
                {
                    TreeViewItem currentItem = item.Items[i] as TreeViewItem;
                    //currentItem.IsExpanded = false;
                    ReadChildren(currentItem);
                }
                catch
                {
                    continue;
                }
            }
        }

        private List<DirectoryInfo> CheckUntil(TreeViewItem item, bool IsChecked)
        {
            List<DirectoryInfo> folders = new List<DirectoryInfo>();
            for(int i=0;i<item.Items.Count;i++)
            {
                try
                {
                    TreeViewItem currentItem = item.Items[i] as TreeViewItem;
                    DirectoryInfo dir = currentItem.Tag as DirectoryInfo;
                    folders.Add(dir);
                    TreeViewItemProps.SetIsChecked(currentItem, IsChecked);
                    folders.AddRange(CheckUntil(currentItem, IsChecked));
                }
                catch {
                    continue;
                }
            }
            return folders;
        }


    }
}
